#pragma once
#include <iostream>
#include <stdarg.h>
#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFFSIZE1 1024
#define TIMESIZE 128

enum
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};

enum
{
    Screen = 11,
    OneFile,
    ClassFile
};

// 日志 （等级，时间 ，内容）
const int defaultmode = Screen;
const std::string defaultpathname = "log.";
const std::string defaultdir = "log";
class Log
{
public:
    Log(int mode = defaultmode)
        : _mode(mode)
    {
        mkdir(defaultdir.c_str(), 0775);
    }
    // 修改输出模式
    void Enable(int mode)
    {
        _mode = mode;
    }
    std::string LevelToString(int level)
    {
        switch (level)
        {
        case Debug:
            return "Debug";
            break;
        case Info:
            return "Info";
            break;
        case Warning:
            return "Warning";
            break;
        case Error:
            return "Error";
            break;
        case Fatal:
            return "Fatal";
            break;
        default:
            return "Unknow";
            break;
        }
    }

    void WriteLogToOneFile(const std::string &path, const std::string &logstr)
    {
        umask(0000);
        int fd = open(path.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666);
        if (fd == -1)
            return;
        write(fd, logstr.c_str(), logstr.size());
        close(fd);
    }
    void WriteLogToClassFile(int level, const std::string &logstr)
    {
        std::string path = defaultdir;
        path += "/";
        path += defaultpathname;
        path += LevelToString(level);
        WriteLogToOneFile(path, logstr);
    }

    void WriteLog(int level, const std::string &logstr)
    {
        switch (_mode)
        {
        case Screen:
            std::cout << logstr << std::endl;
            break;
        case OneFile:
            WriteLogToOneFile(defaultpathname + "all", logstr);
            break;
        case ClassFile:
            WriteLogToClassFile(level, logstr);
            break;
        default:
            break;
        }
    }

    std::string TimeStampExLocalTime()
    {
        time_t tm = time(nullptr);
        struct tm *stm = localtime(&tm);
        char buffer[TIMESIZE];
        snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d",
                 stm->tm_year + 1900, stm->tm_mon + 1, stm->tm_mday,
                 stm->tm_hour, stm->tm_min, stm->tm_sec);
        return buffer;
    }

    void LogMessage(int level, std::string rightbuff) // 类C的一个日志接口
    {
        char leftbuff[BUFFSIZE1];
        std::string curtime = TimeStampExLocalTime();
        std::string lstr = LevelToString(level);
        snprintf(leftbuff, sizeof(leftbuff), "[%s] [%s]", lstr.c_str(), curtime.c_str());
        char buff[BUFFSIZE1 * 2];
        snprintf(buff, sizeof(buff), "%s %s", leftbuff, rightbuff.c_str());
        WriteLog(level, buff);
    }

    void operator()(int level, const char *format, ...)
    {
        char rightbuff[BUFFSIZE1];
        va_list args;           // void* char* 定义指针
        va_start(args, format); // 指向..部分
        vsnprintf(rightbuff, sizeof(rightbuff), format, args);
        va_end(args); // args = nullptr;
        LogMessage(level, rightbuff);
    }
    ~Log()
    {
    }

private:
    int _mode;
    std::string _pathname;
};

Log lg;

class Conf
{
public:
    Conf()
    {
        lg.Enable(Screen);
    }
    ~Conf()
    {
    }
private:
};

Conf con;
